///\file main.cpp
///\brief contient le programme principal
///\author Allan BLANCHARD
#include "housegl.hh"
#include "evolmodel.hh"
#include "depmodel.hh"

#include <cstdlib>
#include <ctime>
#include <vector>

#include <iostream>

float ysecondes;
float zsecondes;

float yminutes;
float zminutes;

float yheures;
float zheures;

///\brief
///fonction d'évolution de l'hélice au entreetage
void rotationhelice(){
  static float angle = 0;
  glRotatef(angle, 0, 1, 0);
  
  angle += .5;
  if(angle > 360) angle = .5;
}

void rotationsecondes(){
  time_t secondes;
  tm instant;
  
  time(&secondes);
  instant=*localtime(&secondes);

  glRotatef(instant.tm_sec * 6, 0, 1, 0);
  glTranslatef(0, ysecondes, zsecondes);
}

void rotationminutes(){
  time_t secondes;
  tm instant;
  
  time(&secondes);
  instant=*localtime(&secondes);

  glRotatef(instant.tm_min * 6, 0, 1, 0);
  glTranslatef(0, yminutes, zminutes);
}

void rotationheures(){
  time_t secondes;
  tm instant;
  
  time(&secondes);
  instant=*localtime(&secondes);

  glRotatef(instant.tm_hour * 30, 0, 1, 0);
  glTranslatef(0, yheures, zheures);
}

///\brief programme principal
///
int main(int argc, char* argv[]){
  srand(time(0));

  ///- initialisation de glut
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE);

  ///- création de HouseGL
  HouseGLCreator mgc(1024,600,"K-House-GL");
  HouseGL* gl = mgc.getInstanceOfHouseGL();

  ///- initialisation de GLEW (VBO)
  glewInit();
  
  ///- chargemement des Modèles 
  DepModel sol("models/sol.off");
  DepModel plafond("models/sol.off");
  DepModel entreetage("models/plafond.off");
  DepModel muro("models/mur.off");
  DepModel mure("models/mur.off");
  DepModel murn("models/mur.off");
  DepModel murs("models/mur.off");

  DepModel escalier("models/escalier.off");
  DepModel barriere("models/barriere.off");
  DepModel tablesimple("models/tablesimple.off");
  DepModel tablalapin("models/tablesimple.off");
  DepModel lampe("models/lampe.off");
  DepModel cage("models/cage.off");
  DepModel lapin("models/lapin.off");
  DepModel table("models/table.off");
  DepModel chaise1("models/chaise.off");
  DepModel chaise2("models/chaise.off");
  DepModel verreeau("models/verre.off", true);
  DepModel journal("models/journal.off");

  DepModel horloge("models/horloge.off");
  EvolModel secondes("models/secondes.off", rotationsecondes);
  EvolModel minutes("models/minutes.off", rotationminutes);
  EvolModel heures("models/heures.off", rotationheures);

  DepModel xandria("models/xandria.off");
  EvolModel helice("models/helice.off", rotationhelice);

  DepModel portequeue("models/portequeue.off");
  DepModel bar("models/bar.off");

  DepModel billard("models/billard.off");
  std::vector<DepModel*> boules;
  for(int i = 0; i < (rand()%8)+4; i++)
    boules.push_back(new DepModel("models/boule.off"));
  std::vector<DepModel*> queues;
  for(int i = 0; i < 4; i++)
    queues.push_back(new DepModel("models/queue.off"));

  DepModel queue("models/queue.off");
  DepModel verre("models/verrewhisky.off", true);

  std::vector<DepModel*> bouteilles;
  for(int i = 0; i < (rand()%4)+2; i++)
    bouteilles.push_back(new DepModel("models/bouteille.off", true));
  std::vector<DepModel*> tousverres;
  for(int i = 0; i < (rand()%6)+6; i++)
    tousverres.push_back(new DepModel("models/verrewhisky.off", true));

  ///- changement des couleurs (au besoin)
  for(unsigned int i = 0; i < boules.size(); i++){
    boules[i]->setSpecular(1.,1.,1.);
    boules[i]->setShininess(10);

    if(rand()%100 < 50){
      boules[i]->setAmbient(.6,.0,.0);
      boules[i]->setDiffuse(.6,.0,.0);
    }
    else{
      boules[i]->setAmbient(.5,.4,.0);
      boules[i]->setDiffuse(.5,.4,.0);
    }
  }
  boules[0]->setAmbient(.6,.6,.6);
  boules[0]->setDiffuse(.6,.6,.6);
  boules[1]->setAmbient(.0,.0,.0);
  boules[1]->setDiffuse(.0,.0,.0);

  for(unsigned int i = 0; i < bouteilles.size(); i++){
    bouteilles[i]->setAmbient(.7*((rand()%50)+50)/100,
			      .7*((rand()%50)+50)/100,
			      .7*((rand()%50)+50)/100,
			      .3);
    bouteilles[i]->setDiffuse(.0,.0,.0,.3);
    bouteilles[i]->setEmission(.0,.0,.0,.0);
    bouteilles[i]->setSpecular(.2,.2,.2,.3);
  }

  verre.setAmbient(.7,.7,.7,.3);
  verre.setDiffuse(.0,.0,.0,.3);
  verre.setEmission(.0,.0,.0,.0);
  verre.setSpecular(.2,.2,.2,.3);

  verreeau.setAmbient(.7,.7,.7,.3);
  verreeau.setDiffuse(.0,.0,.0,.3);
  verreeau.setEmission(.0,.0,.0,.0);
  verreeau.setSpecular(.2,.2,.2,.3);

  journal.setAmbient(.8,.8,.8);
  journal.setDiffuse(.9,.9,.9);

  for(unsigned int i = 0; i < tousverres.size(); i++){
    tousverres[i]->setAmbient(.7,.7,.7,.3);
    tousverres[i]->setDiffuse(.0,.0,.0,.3);
    tousverres[i]->setEmission(.0,.0,.0,.0);
    tousverres[i]->setSpecular(.2,.2,.2,.3);
  }

  table.setAmbient(.6,.6,.6);
  table.setDiffuse(.3,.3,.3);
  table.setShininess(200);

  lapin.setAmbient(.22,.11,.0);
  lapin.setDiffuse(.22,.11,.0);
  
  helice.setAmbient(.0,.0,.0);
  helice.setDiffuse(.0,.0,.0);
  helice.setSpecular(1.,1.,1.);
  helice.setShininess(10);
  
  barriere.setAmbient(.15,.1,.0);
  barriere.setDiffuse(.15,.1,.0);
  barriere.setSpecular(1.,1.,1.);
  barriere.setShininess(10);
  
  secondes.setAmbient(.0, .0, .0);
  secondes.setDiffuse(.0, .0, .0);
  
  minutes.setAmbient(.0, .0, .0);
  minutes.setDiffuse(.0, .0, .0);

  heures.setAmbient(.0, .0, .0);
  heures.setDiffuse(.0, .0, .0);

  lampe.setAmbient(.2, .0, .0);
  lampe.setDiffuse(.6, .0, .0);
  lampe.setEmission(.2, .0, .0);
  lampe.setSpecular(1.,1.,1.);
  lampe.setShininess(10);

  ///- redimensionnements des modèles
  sol.resize(4);
  plafond.resize(4);
  muro.resize(4);
  xandria.resize(2);
  mure.resize(4);
  murn.resize(4);
  murs.resize(4);
  lampe.resize(0.3);
  horloge.resize(0.5);
  secondes.resize(0.25);
  minutes.resize(0.20);
  heures.resize(0.15);
  escalier.resize
    (murs.getymax()/escalier.getymax()/2);
  barriere.resize
    ((murs.getxmax()-murs.getxmin())*0.70);
  entreetage.resize(4);
  bar.resize(2);

  billard.resize((muro.getymax()-muro.getymin())/2.5);
  verre.resize((billard.getymax()-billard.getymin())/5);
  for(unsigned int i = 0; i < tousverres.size(); i++)
    tousverres[i]->resize((billard.getymax()-billard.getymin())/5);
  
  for(unsigned int i = 0; i < boules.size(); i++)
    boules[i]->resize((billard.getzmax()-billard.getzmin())/30);
  
  queue.resize(1.5*(billard.getxmax()-billard.getxmin()));
  for(unsigned int i = 0; i < queues.size(); i++)
    queues[i]->resize(1.5*(billard.getxmax()-billard.getxmin()));
  
  portequeue.resize((billard.getxmax()-billard.getxmin())*0.75);

  for(unsigned int i = 0; i < bouteilles.size(); i++)
    bouteilles[i]->resize((billard.getymax()-billard.getymin())/2);

  chaise1.resize(0.95);
  chaise2.resize(0.95);
  verreeau.resize((table.getymax()-table.getymin())/5);
  journal.resize(0.35);
  tablesimple.resize(1.3);
  lapin.resize((billard.getymax()-billard.getymin())/1.25);
  cage.resize(lapin.getymax()/cage.getymax());
  helice.resize((muro.getymax()-muro.getymin())/2.5);
  
  ///- mise en place des relations de dépendance entre modèles
  muro.dependOn(sol);  
  plafond.dependOn(sol);
  mure.dependOn(muro); 
  escalier.dependOn(sol);
  barriere.dependOn(entreetage);
  horloge.dependOn(muro);
  secondes.dependOn(horloge);
  minutes.dependOn(horloge);
  heures.dependOn(horloge);

  murn.dependOn(sol);
  murs.dependOn(murn);

  portequeue.dependOn(mure);
  xandria.dependOn(muro);
  bar.dependOn(murn);

  for(unsigned int i = 0; i < bouteilles.size(); i++)
    bouteilles[i]->dependOn(bar);
  for(unsigned int i = 0; i < tousverres.size(); i++)
    tousverres[i]->dependOn(bar);

  billard.dependOn(sol);

  table.dependOn(entreetage);
  verreeau.dependOn(table);
  journal.dependOn(table);

  chaise1.dependOn(entreetage);
  chaise2.dependOn(entreetage);

  tablesimple.dependOn(entreetage);
  tablalapin.dependOn(tablesimple);
  lampe.dependOn(tablalapin);
  cage.dependOn(tablalapin);
  lapin.dependOn(cage);  

  verre.dependOn(billard);
  for(unsigned int i = 0; i < boules.size(); i++)
    boules[i]->dependOn(billard);
  for(unsigned int i = 0; i < queues.size(); i++)
    queues[i]->dependOn(portequeue);
  queue.dependOn(billard);

  helice.dependOn(entreetage);
  ///- placement des modèles
    
  //placement en hauteur des murs
  Translation hmur(0, muro.getymax(), 0);
  muro.addTranslation(hmur);
  murn.addTranslation(hmur);

  //placement du mur ouest
  Translation mo1(0, 0, sol.getzmin());
  muro.addTranslation(mo1);
  
  //placement du mur est
  Translation me1(0, 0, sol.getzmax()*2);
  mure.addTranslation(me1);

  //placement du mur nord
  Translation mn1(sol.getxmin(), 0, 0);
  Rotation rmn1(90, 0, 1, 0);
  murn.addTranslation(mn1);
  murn.addRotation(rmn1);

  //placement du mur sud
  Translation ms1(0, 0, sol.getzmax()*2);
  murs.addTranslation(ms1);
  
  //placement horloge
  Rotation rhorloge(-90, 1, 0, 0);
  Translation thorloge(0, 3*muro.getymax()/4, horloge.getymax()+0.01);
  
  horloge.addTranslation(thorloge);
  horloge.addRotation(rhorloge);
  
  //placement aiguille secondes
  ysecondes = secondes.getymin()+horloge.getymin();
  zsecondes = secondes.getzmax();

  //placement aiguille minutes
  yminutes = minutes.getymin()+horloge.getymin();
  zminutes = minutes.getzmax();
  
  //placement aiguille heures
  yheures = heures.getymin()+horloge.getymin();
  zheures = heures.getzmax();
  
  //placement plafond
  Translation solplaf(0, 2*mure.getymax(), 0);
  plafond.addTranslation(solplaf);
  
  //placement poster xandria
  Translation xa(0.25*(xandria.getxmin()-xandria.getxmax()), 
		 2*xandria.getymin(), 0.01);
  xandria.addTranslation(xa);

  //placement barriere
  Translation barriereetage(entreetage.getxmax()-barriere.getxmax(), 
			    barriere.getymax()+0.01, 
			    barriere.getzmax()*0.4);
  barriere.addTranslation(barriereetage);
 
  //placement escalier
  Translation solesc(sol.getxmax()-escalier.getxmax()-0.01, 
		     escalier.getymax()+0.01, 
		     -(escalier.getzmax()-escalier.getzmin())*0.125+0.01);
  escalier.addTranslation(solesc);

  //placement du entreetage
  Translation murentreetage(-(entreetage.getzmax()-entreetage.getzmin())*0.125, 
			 (muro.getymax()-muro.getymin())/2, 
			 0);
  entreetage.addTranslation(murentreetage);

  //placement bar
  Translation barsol(0, -muro.getymax()+bar.getymax()+0.01, bar.getzmax()+0.01);
  bar.addTranslation(barsol);

  //placements bouteilles
  std::vector<Translation>barbouteille;
  for(unsigned int i = 0; i < bouteilles.size(); i++){
    Translation t(bar.getxmin()+
		  (i+1)*(bar.getxmax()-bar.getxmin())/((bouteilles.size()+1)),
		  bar.getymax(),
		  0);
    barbouteille.push_back(t);
  }
  for(unsigned int i = 0; i < bouteilles.size(); i++)
    bouteilles[i]->addTranslation(barbouteille[i]);

  //placements tousverres
  std::vector<Translation>barverres;
  for(unsigned int i = 0; i < tousverres.size(); i++){
    Translation t(bar.getxmin()+
		  (i+1)*(bar.getxmax()-bar.getxmin())/((tousverres.size()+1)),
		  bar.getymax()/5,
		  0);
    barverres.push_back(t);
  }
  for(unsigned int i = 0; i < tousverres.size(); i++)
    tousverres[i]->addTranslation(barverres[i]);

  //placement porte-queue
  Rotation rotportequeue(90,0,1,0);
  portequeue.addRotation(rotportequeue);
  Translation murportequeue
    (portequeue.getxmax()+0.01,
     -(muro.getymax()-muro.getymin())/4-billard.getymax()/2,
     0);
  portequeue.addTranslation(murportequeue);

  //placements queues
  Rotation rotqueuesporte(-90, 0, 1, 0);
  std::vector<Translation>translatqueues;
  for(unsigned int i = 0; i < queues.size(); i++){
    queues[i]->addRotation(rotqueuesporte);
    Translation t(0, portequeue.getymax()*0.75 - i*portequeue.getymax()*0.4, 0);
    translatqueues.push_back(t);
  }
  for(unsigned int i = 0; i < translatqueues.size(); i++)
    queues[i]->addTranslation(translatqueues[i]);
  
  //placement billard
  Translation solbillard(xandria.getxmin()/2, -billard.getymin(), 0);
  billard.addTranslation(solbillard);

  //placement boules
  std::vector<Translation>aleaboules;
  for(unsigned int i = 0; i < boules.size(); i++){
    float x = billard.getxmax()*0.6*(static_cast<float>(rand()%100)/100);
    float z = billard.getzmax()*0.6*(static_cast<float>(rand()%100)/100);
    
    if(rand()%100 < 50) x *= -1;
    if(rand()%100 < 50) z *= -1;

    Translation alea(x,billard.getymax(),z);
    aleaboules.push_back(alea);
  }
  for(unsigned int i = 0; i < aleaboules.size(); i++)
    boules[i]->addTranslation(aleaboules[i]);
  
  //placement queue
  Translation billardqueue(0, billard.getymax()-queue.getymin(), 0);
  queue.addTranslation(billardqueue);
  Rotation qr(rand()%90, 0, 1, 0);
  queue.addRotation(qr);

  //placement verre
  Translation billardverre
    ((billard.getxmin()+verre.getxmax())*static_cast<float>(rand()%100)/100, 
     billard.getymax()-verre.getymin(), 
     billard.getzmax()+verre.getzmin()*2);
  verre.addTranslation(billardverre);
  
  //placement tablesimple
  Rotation rotsimple(180, 0, 1, 0);
  Translation etagetsimple(0,
			   tablesimple.getymax()+0.01, 
			   entreetage.getzmax()-tablesimple.getzmax()-0.01);
  tablesimple.addTranslation(etagetsimple);
  tablesimple.addRotation(rotsimple);

  //placement de la tablalapin (melange de cage et de table);
  Translation tabletotable(0, tablesimple.getymax()+tablalapin.getymax(), 0);
  tablalapin.addTranslation(tabletotable);

  //placement lampe
  Translation lampetable(0, tablalapin.getymax()-lampe.getymin(), 0);
  lampe.addTranslation(lampetable);

  //placement tablagens ^^
  Rotation rtable(45, 0, 1, 0);
  Translation etagetable(0, table.getymax()+0.01, table.getzmin());
  table.addTranslation(etagetable);
  table.addRotation(rtable);

  //placement chaise1
  Rotation rchaise1(-90, 0, 1, 0);
  Rotation rchaise12(180, 0, 1, 0);
  Translation tchaise12(0, 0, 2*chaise1.getzmax());
  Translation tchaise1(table.getxmax()+chaise1.getxmax(), 
		       chaise1.getymax()+0.01,
		       0);
  chaise1.addRotation(rchaise12);
  chaise1.addTranslation(tchaise1);
  chaise1.addTranslation(tchaise12);
  chaise1.addRotation(rchaise1);

  //placement chaise 2
  Translation tchaise2(0,0,table.getzmin());
  Rotation rchaise2(-90, 0, 1, 0);
  chaise2.addTranslation(tchaise2);
  chaise2.addRotation(rchaise2);
  chaise2.addTranslation(tchaise1);
  chaise2.addRotation(rchaise1);  

  //placement verre à gens
  Translation verreeautable(2*verreeau.getxmax(), 
			    table.getymax()+verreeau.getymax(), 
			    3*verreeau.getzmax());
  verreeau.addTranslation(verreeautable);

  //placement journal
  Rotation rjournal(-90, 0, 1, 0);
  Translation tjournal(journal.getxmin(), table.getymax()+journal.getymax(), 0);
  journal.addTranslation(tjournal);
  journal.addRotation(rjournal);

  //placement helice
  Translation heliceentreetage(0, -0.01+helice.getymin(), 0);
  helice.addTranslation(heliceentreetage);
  
  ///- ajout des modèles à l'HouseGL
  gl->addModel(sol);
  gl->addModel(entreetage);
  gl->addModel(billard);
  gl->addModel(tablesimple);
  gl->addModel(tablalapin);
  gl->addModel(lampe);
  gl->addModel(cage);
  gl->addModel(lapin);
  gl->addModel(table);
  gl->addModel(chaise1);
  gl->addModel(chaise2);
  gl->addModel(journal);
  gl->addModel(helice);
  gl->addModel(muro);
  gl->addModel(mure);
  gl->addModel(murn);
  gl->addModel(murs);
  gl->addModel(plafond);
  gl->addModel(escalier);
  gl->addModel(barriere);
  gl->addModel(xandria);
  gl->addModel(bar);
  gl->addModel(portequeue);
  gl->addModel(queue);
  for(unsigned int i = 0; i < boules.size(); i++)
    gl->addModel(*boules[i]);
  for(unsigned int i = 0; i < queues.size(); i++)
    if(rand()%100 < 75)
      gl->addModel(*queues[i]);
  gl->addModel(horloge);
  gl->addModel(secondes);
  gl->addModel(minutes);
  gl->addModel(heures);

  for(unsigned int i = 0; i < bouteilles.size(); i++)
    gl->addModel(*bouteilles[i]);
  for(unsigned int i = 0; i < tousverres.size(); i++)
    gl->addModel(*tousverres[i]);
  gl->addModel(verre);
  gl->addModel(verreeau);

  std::cout<<"Nombre total de sommets chargés : "<<Model::totalsommets
	   <<std::endl;
  std::cout<<"Nombre total de faces chargées  : "<<Model::totalfaces
	   <<std::endl;

  ///- Lancement du rendu 
  gl->render();

  return 0;
}
